/*
 Copyright (c) 2008 TPSi
 Alex Iskander
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 
 */
#ifndef BINDABLE_BINDABLE_FUNCTIONS_GETTER_H_
#define BINDABLE_BINDABLE_FUNCTIONS_GETTER_H_

#include "GetterFunction.h"

namespace Bind
{
	
	template <class Type>
	class Getter
	{
	public:
		/**
		 \fn Getter();
		 \brief Creates a new unset getter (function pointer is null).
		 */
		Getter();
		
		/**
		 \fn Getter(const Getter &getter);
		 \brief Copy constructor.
		 */
		Getter(const Getter<Type> &getter);
		
		
		/**
		 \fn Getter(Bind::GetterFunction<Type> *function);
		 \brief Creates a new getter with the supplied function.
		 */
		Getter(Bind::GetterFunction<Type> *function);

		/**
		 \fn operator() (const Bindable *This) const;
		 \brief Runs the getter if it is set, or returns a default value.
		 */
		Type operator() (const Bindable *This) const;
		
		/**
		 \fn operator=(GetterFunction<Type> *function);
		 \brief Assigns a new getter. Assign to NULL to unset.
		 */
		void operator=(GetterFunction<Type> *function);
		
		/**
		 \fn operator=(Getter<Type> &getter);
		 \brief Assign a new getter from another Getter.
		 */
		void operator=(Getter<Type> &getter);
		
		/**
		 \fn unset();
		 \brief Unsets the getter. Equivalent to calling getter = NULL;
		 */
		void unset();
		
		/**
		 \fn isSet() const;
		 \brief Returns true if the function is not equal to NULL; otherwise 
		 false.
		 */
		bool isSet() const;
		
		/**
		 \fn ~Getter();
		 \brief Destructor.
		 */
		~Getter();
		
	protected:
		GetterFunction<Type> *getter;
	};

	template <class Type>
	Getter<Type>::Getter()
	{
		//initialize getter to null
		this->getter = NULL;
	}
	
	template<class Type>
	Getter<Type>::Getter(const Getter &getter)
	{
		//copy getter
		this->getter = getter->getter;
		
		//mark
		this->getter->copy();
	}
	
	
	template <class Type>
	Getter<Type>::Getter(GetterFunction<Type> *function)
	{
		//initialize the getter to the function supplied.
		this->getter = function;
		
		//mark
		this->getter->copy();
	}
	
	template <class Type> Type 
	Getter<Type>::operator() (const Bindable *This) const
	{
		//if there is a getter
		if (getter)
			//return it
			return (*getter)(This);
		
		//otherwise, return a blank value.
		return Type();
	}
	
	template <class Type> void
	Getter<Type>::operator=(Getter<Type> &function)
	{
		(*this) = function.getter;
	}
	
	template <class Type> void
	Getter<Type>::operator=(GetterFunction<Type> *function)
	{
		//mark first
		if (function)
			function->copy();
		
		//if there is a getter
		if (this->getter)
			//get rid of it
			this->unset();
		
		//set the new one.
		this->getter = function;
	}
	
	template <class Type> inline void
	Getter<Type>::unset()
	{
		//if there is a getter
		if (this->getter)
		{
			if (this->getter->destroy())
			{
				delete this->getter;
			}
		}
		
		//make sure it is clear
		this->getter = NULL;
	}
	
	template <class Type> inline bool
	Getter<Type>::isSet() const
	{
		//if there is a getter return true; otherwise false.
		return (this->getter ? true : false);
	}
	
	template <class Type> 
	Getter<Type>::~Getter()
	{
		//if there is a getter
		if (this->getter)
			//destroy it.
			this->unset();
	}
}

#endif